package com.wust.dns_resolver.utils;

/**
 * DNS响应解析器
 */
public class DnsResponseParser {
    private byte[] data;  // 存储DNS响应数据的字节数组
    private int position; // 保存当前读取位置


    //构造函数
    public DnsResponseParser(byte[] data) {
        this.data = data;
        this.position = 0;
    }

    // 跳过指定长度的字节
    public void skip(int length) {
        position += length;
    }

    //读取一个16位的短整型数据(两个字节)
    public int readShort() {
        int value = ((data[position] & 0xFF) << 8) | (data[position + 1] & 0xFF);
        position += 2;
        return value;
    }

    public long readInt() {
        long value = ( (data[position] & 0xFF) << 24) |
                ((data[position + 1] & 0xFF) << 16) |
                ((data[position + 2] & 0xFF) << 8) |
                (data[position + 3] & 0xFF);
        position += 4;
        return value;
    }

    public byte[] readBytes(int length) {
        byte[] result = new byte[length];
        System.arraycopy(data, position, result, 0, length);
        position += length;
        return result;
    }

    public String readDomainName() {
        //创建 StringBuilder 对象 name 用于拼接域名
        StringBuilder name = new StringBuilder();
        int length;

        //data[position] & 0xFF 确保无符号处理
        while ((length = data[position] & 0xFF) > 0) {
            // 处理DNS消息压缩
            //若 length & 0xC0 == 0xC0，表示当前字节是压缩指针的高 8 位
            if ((length & 0xC0) == 0xC0) {
                if (name.length() > 0) {
                    name.append(".");
                }
                //计算偏移量
                //将高 6 位（0x3F 掩码）与下一个字节组合，得到目标偏移量（例如 0x1234）
                int offset = ((length & 0x3F) << 8) | (data[position + 1] & 0xFF);
                position += 2;

                // 递归读取压缩的域名
                //保存当前解析位置 savedPosition（如当前位置是 0x56）
                int savedPosition = position;
                //将 position 设置为 offset（如跳转到 0x1234）
                position = offset;
                //在 offset 处调用 readDomainName()，解析被压缩的域名部分
                name.append(readDomainName());
                //将 position 重置为 savedPosition（回到 0x56），确保后续解析不受递归影响。
                position = savedPosition;
                return name.toString();
            }

            //处理普通标签
            position++;
            if (name.length() > 0) {
                name.append(".");
            }
            name.append(new String(data, position, length));
            position += length;
        }

        position++;
        return name.toString();
    }
}
